<?php
/**
 * Class Database
 * Mở rộng dựa trên thư viện PDO để đơn giản hóa các thao tác với dữ liệu MySQL
 * Test comment
 */
class Database extends PDO
{
    private $sql;
    private $bind;

    public function __construct()
    {
        $option = array(
            // Sử dụng chế độ ngoại lệ
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            // Bật kết nối mã hóa utf8
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"
        );

        $dsn = 'mysql:host=' . DB_HOSTNAME . ';dbname=' . DB_DATABASE;
        parent::__construct($dsn, DB_USERNAME, DB_PASSWORD, $option);
    }

    public function debug()
    {
        var_dump($this);
    }

    public function __toString()
    {
        $this->debug();
    }

    /**
     * Trả về một mảng được tạo từ biến $bind
     * @param $bind
     * @return array
     */
    protected  function cleanup($bind)
    {
        if (!is_array($bind)) {
            if (!empty($bind)) {
                $bind = array($bind);
            } else {
                $bind = array();
            }
        }
        return $bind;
    }

    /**
     * Lấy danh sách cột hợp lệ trong bảng $table và mảng $info
     * @param $table
     * @param $info
     * dạng array (
     *  column => value,
     * ...
     * )
     * @return array
     */
    protected  function filter($table, $info)
    {
        $sql = "DESCRIBE {$table};";
        if (($list = $this->run($sql)) !== false) {
            $fields = array();
            foreach ($list as $record) {
                $fields[] = $record['Field'];
            }
            return array_values(array_intersect($fields, array_keys($info)));
        }
        return array();
    }

    /**
     * Thực hiện câu lệnh sql
     * @param $sql
     * @param string $bind
     * @return array|bool|int
     */
    public function run($sql, $bind = '')
    {

        $this->sql = trim($sql);
        $this->bind = $this->cleanup($bind);

        $pdostmt = $this->prepare($this->sql);
        // Thực thi thành công, trả về dữ liệu
        $r = $pdostmt->execute($this->bind);

        if ( $r !== false) {
            // Nếu là SQL dạng select, describe
            if (preg_match('/^(select|describe)/i', $this->sql)) {
                return $pdostmt->fetchAll(PDO::FETCH_ASSOC);
            } elseif (preg_match('/^(delete|insert|update)/i', $this->sql)) {
                return $pdostmt->rowCount();
            }
        }

        return false;
    }

    public function executeScalar($sql, $bind ='')
    {
        $result = $this->run($sql, $bind);
        if ($result !== false && count($result) > 0) {
            $firstRow = $result[0];
            $cols = array_keys($firstRow);
            return $firstRow[$cols[0]];
        } elseif (round($result) == 0) {
            return null;
        }
    }

    public function disconnect()
    {
        $this->_instance = null;
    }

    public function __destruct()
    {
        $this->disconnect();
    }
}